namespace designpatternsplusplus.decorator
{
    #region

    using System;
    using designpatternsplus.contracts;
    using DomainEntities;
    using RepositoryServices;
    using Support;

    #endregion

    /// <summary>
    /// This is our market selling all things interesting
    /// to all with money and interest
    /// </summary>
    public sealed class CoolCrapMarket : ICoolCrapMarket
    {
        static readonly CoolCrapMarket store;
        static OnStoreEventDelegate OnSaleTransaction = delegate {};
        static OnStoreEventDelegate OnTraceDetail = delegate {};
        readonly ProductRepository productRepository = new ProductRepository();
        readonly ShoppingCartSection rowsOfCartAisles;

        // So imagine the store layout:
        //
        //  Carts  are in row as such
        //      
        //      r1    r2    r3
        //      c1    c4    c7
        //      c2    c5    c8
        //      c3    c6    c9
        //
        //      Store Front Doors 
        //     -----   ----- ----


        // We have three 'stacks/aisles defined as r1, r2 r3 and 9 carts set into the rows
        // in the lifo stacks.

        /// <summary>
        /// Initializes a new instance of the <see cref="CoolCrapMarket"/> class.
        /// Here we would use the same strategy pattern for injecting loggers
        /// </summary>
        static CoolCrapMarket()
        {
            store = MarketStaffMember.OpenStore();
        }

        internal CoolCrapMarket(ShoppingCartSection rowsOfCartAisles)
        {
            IsOpen = true;

            this.rowsOfCartAisles = rowsOfCartAisles;
        }

        /// <summary>
        /// Gets or sets a value indicating whether [trace on].
        /// </summary>
        /// <value><c>true</c> if [trace on]; otherwise, <c>false</c>.</value>
        public static bool TraceOn { get; set; }

        /// <summary>
        /// Gets the store singleton of organic and certified insect
        /// free code (free range programmers!)
        /// </summary>
        /// <value>The get.</value>
        public static CoolCrapMarket Get
        {
            get { return store; }
        }

        /// <summary>
        /// Gets the products carried.
        /// </summary>
        /// <value>The products carried.</value>
        public IProductRepository ProductsCarried
        {
            get { return productRepository; }
        }

        ///<summary>
        ///</summary>
        public bool IsOpen { get; internal set; }

        /// <summary>
        /// Gets the shopping cart.
        /// </summary>
        /// <value>The shopping cart.</value>
        public IShoppingCart ShoppingCart
        {
            get
            {
                // A pop from the stack 
                // is a grab of a cart froim the 'top'
                //of that row

                foreach (var row in rowsOfCartAisles)
                {
                    if (row.Count > 0)
                        return row.Pop();
                }

                throw new InvalidOperationException
                    ("You are out of carts! You just got fired");
            }
        }

        /// <summary>
        /// Gets or sets the manager.
        /// </summary>
        /// <value>The manager.</value>
        public IMarketStaffMember Manager { get; internal set; }


        /// <summary>
        /// Occurs when [on post sale transaction].
        /// </summary>
        public static event OnStoreEventDelegate OnPostSaleTransaction
        {
            add
            {
                if (!OnSaleTransaction.ObserverHooked(value))
                    OnSaleTransaction += value;
            }
            remove { OnSaleTransaction -= value; }
        }

        public static event OnStoreEventDelegate OnTraceDetailMessage
        {
            add
            {
                if (!OnTraceDetail.ObserverHooked(value))
                    OnTraceDetail += value;
            }
            remove { OnTraceDetail -= value; }
        }

        /// <summary>
        /// Checkout the specified cart.
        /// CHA CHING
        /// </summary>
        /// <param name="cart">The basket.</param>
        /// <returns></returns>
        public static SalesReceipt Checkout(IShoppingCart cart)
        {
            return GenerateSalesRecord(DomainEntities.ShoppingCart.CreateDecoratorChain(cart));
        }

        /// <summary>
        /// Generates the internal sales record.
        /// Must keep the accountant happy
        /// I can add inventory tracking, really.
        /// Alerts on low stock? Hmm. Second interview perhaps?
        /// </summary>
        /// <param name="cart">The basket.</param>
        /// <returns></returns>
        static SalesReceipt GenerateSalesRecord(IShoppingCart cart)
        {
            // Actually do the work here. Below is supporting audit, event dispatch and return
            // of receipt

            var _transactionRecord = new SalesReceipt(cart);
            OnSaleTransaction(_transactionRecord.ToString());
            return _transactionRecord;
        }
    }
}